<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>WebGL 1000个随机点</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            overflow: hidden;
            background-color: #000;
        }

        canvas {
            display: block;
            width: 100vw;
            height: 100vh;
        }
    </style>
</head>

<body>
    <canvas id="webgl-canvas"></canvas>

    <script async>
        // 异步加载着色器文件
        async function loadShaderFile(url) {
            const response = await fetch(url);
            return await response.text();
        }
        // // 顶点着色器源码
        // const vertexShaderSource = `#version 300 es
        //     in vec2 a_position;
        //     in vec3 a_color;

        //     out vec3 v_color;

        //     void main() {
        //         gl_Position = vec4(a_position, 0.0, 1.0);
        //         gl_PointSize = 4.0;
        //         v_color = a_color;
        //     }
        // `;

        // // 片段着色器源码
        // const fragmentShaderSource = `#version 300 es
        //     precision mediump float;

        //     in vec3 v_color;
        //     out vec4 fragColor;
        //     void main() {
        //         fragColor = vec4(v_color, 1.0);
        //     }
        // `;
        // 顶点着色器和片段着色器文件路径

        function createShader(gl, type, source) {
            const shader = gl.createShader(type);
            gl.shaderSource(shader, source);
            gl.compileShader(shader);

            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                console.error('着色器编译错误:', gl.getShaderInfoLog(shader));
                gl.deleteShader(shader);
                return null;
            }

            return shader;
        }

        function createProgram(gl, vertexShader, fragmentShader) {
            const program = gl.createProgram();
            gl.attachShader(program, vertexShader);
            gl.attachShader(program, fragmentShader);
            gl.linkProgram(program);

            if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
                console.error('程序链接错误:', gl.getProgramInfoLog(program));
                gl.deleteProgram(program);
                return null;
            }

            return program;
        }

        async function initWebGL() {
            const vertexShaderSource = await loadShaderFile('sharder/vert/point.vert');
            const fragmentShaderSource = await loadShaderFile('sharder/frag/point.frag');
            const canvas = document.getElementById('webgl-canvas');
            const gl = canvas.getContext('webgl2');

            if (!gl) {
                console.error('WebGL不可用');
                return;
            }

            // 设置画布大小
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            gl.viewport(0, 0, canvas.width, canvas.height);

            // 创建着色器
            const vertexShader =  createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
            const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

            if (!vertexShader || !fragmentShader) return;

            const program = createProgram(gl, vertexShader, fragmentShader);
            if (!program) return;

            // 生成1000个随机点的位置和颜色
            const numPoints = 1000;
            const positions = [];
            const colors = [];

            for (let i = 0; i < numPoints; i++) {
                // 在-1到1之间生成随机位置
                positions.push(Math.random() * 2 - 1);
                positions.push(Math.random() * 2 - 1);

                // 生成随机颜色
                colors.push(Math.random());
                colors.push(Math.random());
                colors.push(Math.random());
            }

            // 创建位置缓冲区
            const positionBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

            // 创建颜色缓冲区
            const colorBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

            // 使用着色器程序
            gl.useProgram(program);

            // 设置位置属性（顶点buffer，a_position为顶点着色器中的a_position属性，
            // 该值会赋给gl_Position变量，gl_Position为内置变量,）
            const positionLocation = gl.getAttribLocation(program, 'a_position');
            gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
            gl.enableVertexAttribArray(positionLocation);
            gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

            // 设置颜色属性
            const colorLocation = gl.getAttribLocation(program, 'a_color');
            gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
            gl.enableVertexAttribArray(colorLocation);
            gl.vertexAttribPointer(colorLocation, 3, gl.FLOAT, false, 0, 0);

            // 设置清除颜色并清除
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT);

            // 绘制点
            gl.drawArrays(gl.POINTS, 0, numPoints);
        }

        // 初始化
        window.addEventListener('load', async () =>
        {
            await initWebGL();
        });

        // 响应窗口大小变化
        window.addEventListener('resize', () => {
            const canvas = document.getElementById('webgl-canvas');
            const gl = canvas.getContext('webgl2');

            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            gl.viewport(0, 0, canvas.width, canvas.height);

            initWebGL();
        });
    </script>
</body>

</html>